// 1. 包声明：指定当前类所属包，遵循"项目域+模块"规范，web包用于存放Spring MVC控制器
package cn.edu.buu.hospital.web;

// 2. 导入依赖类：引入当前控制器所需的实体、服务、工具类等
// 导入科室实体类：封装科室的属性（如科室ID、名称、所属医院等），用于数据传输

import cn.edu.buu.hospital.entity.Department;
import cn.edu.buu.hospital.service.DepartmentService;
import cn.edu.buu.hospital.service.HospitalService;
import com.github.pagehelper.PageInfo;
import jakarta.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;

/**
 * 科室管理控制类
 * 负责处理科室相关的HTTP请求，包括新增科室、查询科室、更新科室、删除科室等功能
 */
// 3. 类注解与声明：标记为Spring MVC控制器，统一映射URL前缀
@Controller
// 类级请求映射：当前类所有方法的URL都以"/department"开头（如"/department/add"）
@RequestMapping("/department")
public class DepartmentController {

    // 4. 依赖注入：自动装配Service层Bean，避免手动创建对象
    // 注入科室服务：处理科室的业务逻辑（如数据库CRUD、业务校验）
    @Autowired
    private DepartmentService departmentService; // 注入科室服务，处理科室相关的业务逻辑

    // 注入医院服务：用于查询所有医院，供科室新增/编辑时的"所属医院"下拉选择
    @Autowired
    private HospitalService hospitalService; // 注入医院服务，用于获取医院信息

    /**
     * 跳转到新增科室页面
     * @param model 模型对象，用于传递数据到视图
     * @param session HTTP会话对象，用于存储临时数据（如之前新增失败的表单数据）
     * @return 科室新增页面的视图路径（由视图解析器定位到具体页面）
     */
    // 5. 方法：跳转到新增科室页面（处理GET请求）
    // GET请求映射：URL为"/department/toAdd"，前端点击"新增科室"按钮触发
    @GetMapping("/toAdd")
    public String toAdd(Model model, HttpSession session) {
        // 向视图传递医院列表：调用医院服务查询所有医院，供新增页"所属医院"下拉框使用
        model.addAttribute("hospitalList", hospitalService.findAll());

        // 从会话中读取临时数据：获取之前新增失败时保存的科室数据（用于表单回显）
        Department addDepartment = (Department) session.getAttribute("addDepartment");
        // 若存在回显数据，传递到视图并移除会话中的临时数据（避免重复回显）
        if (addDepartment != null) {
            model.addAttribute("addDepartment", addDepartment);
            // 移除会话数据：确保下次进入新增页时不会残留旧数据
            session.removeAttribute("addDepartment");
        }

        // 返回新增科室页面的视图路径：视图解析器会找到"backend/department/add.html"（如Thymeleaf模板）
        return "backend/department/add"; // 返回新增科室页面
    }

    /**
     * 新增科室（处理表单提交）
     * @param department 科室实体对象：Spring MVC自动将表单参数绑定到该对象（属性名与表单字段名一致）
     * @param model 模型对象：用于向前端传递错误信息
     * @param session HTTP会话对象：用于存储临时数据（回显表单、成功消息）
     * @return 成功→重定向到科室列表页；失败→返回新增页（带错误信息）
     */
    // 6. 方法：处理新增科室表单提交（处理POST请求）
    // POST请求映射：URL为"/department/add"，新增页表单提交时触发
    @PostMapping("/add")
    public String add(Department department, Model model, HttpSession session) {
        try {
            // 调用服务层新增科室：将业务逻辑委托给Service层，控制器不直接操作数据库
            departmentService.add(department);
            // 新增成功：移除会话中可能残留的回显数据（避免下次新增时干扰）
            session.removeAttribute("addDepartment");
            // 向会话中存入成功消息：供列表页显示"科室添加成功！"提示
            session.setAttribute("successMessage", "科室添加成功！");
            // 重定向到科室列表页：用"redirect:"避免表单重复提交（刷新页面不会重新提交）
            return "redirect:find";
        } catch (RuntimeException e) {
            // 捕获业务异常（如Service层抛出的"科室名称重复"等）
            // 保存用户输入到会话：用于回显表单数据（重定向会丢失Model数据，需用Session）
            session.setAttribute("addDepartment", department);
            // 向视图传递错误消息：显示具体业务异常原因（如"科室名称已存在"）
            model.addAttribute("errorMessage", e.getMessage());
            // 重新传递医院列表：返回新增页时需重新加载下拉数据
            model.addAttribute("hospitalList", hospitalService.findAll());
            // 返回新增页：让用户修正错误后重新提交
            return "backend/department/add";
        } catch (Exception e) {
            // 捕获系统异常（如数据库连接失败、SQL错误等）
            // 保存用户输入到会话：用于表单回显
            session.setAttribute("addDepartment", department);
            // 向视图传递通用错误消息：避免暴露系统细节给用户
            model.addAttribute("errorMessage", "新增失败: " + e.getMessage());
            // 重新传递医院列表：确保新增页下拉框正常显示
            model.addAttribute("hospitalList", hospitalService.findAll());
            // 返回新增页：让用户重试或联系管理员
            return "backend/department/add";
        }
    }

    /**
     * 分页查询科室列表（支持直接访问和条件查询）
     * @param model 模型对象：传递分页数据、查询条件、提示消息
     * @param pageNum 当前页码：从URL获取，默认值为1（首次访问显示第1页）
     * @param condition 查询条件对象：Spring MVC自动绑定表单查询参数（如科室名称、所属医院）
     * @param session HTTP会话对象：获取之前操作的成功/错误消息
     * @return 科室列表页面的视图路径
     */
    // 7. 方法：分页查询科室列表（支持GET/POST请求）
    // 请求映射：URL为"/department/find"，支持GET（直接访问列表）和POST（提交查询条件）
    @RequestMapping(value = "/find", method = {RequestMethod.GET, RequestMethod.POST})
    public String find(Model model,
                       // 绑定URL参数"pageNum"，默认值1（用户未传页码时显示第1页）
                       @RequestParam(value = "pageNum", defaultValue = "1") int pageNum,
                       // 绑定查询条件：前端表单提交的"科室名称""所属医院"等参数自动封装到该对象
                       Department condition,
                       HttpSession session) {
        // 从会话获取并传递成功消息：如新增/修改/删除成功后的提示
        String successMessage = (String) session.getAttribute("successMessage");
        if (successMessage != null) {
            // 传递消息到视图：列表页会显示该消息
            model.addAttribute("successMessage", successMessage);
            // 移除会话消息：确保刷新页面后消息不重复显示
            session.removeAttribute("successMessage");
        }

        // 从会话获取并传递错误消息：如删除失败后的提示
        String errorMessage = (String) session.getAttribute("errorMessage");
        if (errorMessage != null) {
            // 传递错误消息到视图
            model.addAttribute("errorMessage", errorMessage);
            // 移除会话消息：避免重复显示
            session.removeAttribute("errorMessage");
        }

        // 设置每页显示条数：固定为5条（可根据需求改为参数传递）
        int pageSize = 5;

        // 调用服务层分页查询：传入页码、每页条数、查询条件，返回分页结果
        PageInfo<Department> pageInfo = departmentService.find(pageNum, pageSize, condition);
        // 调用服务层查询科室总数量：用于列表页显示"共X个科室"
        long totalDepartments = departmentService.findTotal();

        // 向视图传递数据：供列表页渲染
        model.addAttribute("pageInfo", pageInfo); // 分页结果（当前页数据、总页数等）
        model.addAttribute("condition", condition); // 查询条件（回显到表单，方便用户再次查询）
        model.addAttribute("totalDepartments", totalDepartments); // 科室总数量
        model.addAttribute("hospitalList", hospitalService.findAll()); // 医院列表（查询条件下拉框）
        // 返回科室列表页面视图路径：视图解析器定位到"backend/department/list.html"
        return "backend/department/list"; // 返回科室列表页面
    }

    /**
     * 根据科室ID查询详情（用于编辑页面数据回显）
     * @param deptId 科室ID：从URL获取，前端点击"编辑"按钮时传递
     * @param model 模型对象：传递科室详情到编辑页
     * @param session HTTP会话对象：获取之前修改失败的临时数据
     * @return 科室编辑页面的视图路径
     */
    // 8. 方法：根据ID查询科室（用于编辑，处理GET请求）
    // GET请求映射：URL为"/department/findById?deptId=xxx"，编辑按钮触发
    @GetMapping("/findById")
    public String findById(@RequestParam("deptId") Long deptId, Model model, HttpSession session) {
        // 从会话获取修改失败的临时数据：用于回显之前未保存成功的编辑内容
        Department modifyDepartment = (Department) session.getAttribute("modifyDepartment");

        // 若存在临时数据且ID匹配（确保是当前要编辑的科室），则用临时数据回显
        if (modifyDepartment != null && modifyDepartment.getDeptid().equals(deptId)) {
            // 传递临时数据到视图：避免用户重新输入
            model.addAttribute("department", modifyDepartment);
            // 移除会话临时数据：防止下次编辑其他科室时干扰
            session.removeAttribute("modifyDepartment");
        } else {
            // 无临时数据：调用服务层根据ID查询科室详情
            Department department = departmentService.findById(deptId);
            // 若查询结果为null（如ID不存在），新建对象并设置ID：避免前端空指针异常
            if (department == null) {
                department = new Department();
                department.setDeptid(deptId);
            }
            // 传递查询到的科室数据到视图：编辑页回显科室名称、所属医院等
            model.addAttribute("department", department);
        }

        // 传递医院列表到编辑页：供"所属医院"下拉框使用
        model.addAttribute("hospitalList", hospitalService.findAll());

        // 返回编辑页面视图路径：定位到"backend/department/edit.html"
        return "backend/department/edit"; // 返回编辑页面
    }

    /**
     * 修改科室信息（处理编辑表单提交）
     * @param department 包含更新信息的科室实体：表单提交的新数据自动绑定到该对象
     * @param model 模型对象：传递错误信息到编辑页
     * @param session HTTP会话对象：存储临时数据（回显表单、成功消息）
     * @return 成功→重定向到列表页；失败→返回编辑页（带错误信息）
     */
    // 9. 方法：处理科室修改表单提交（处理POST请求）
    // POST请求映射：URL为"/department/modify"，编辑页表单提交触发
    @PostMapping("/modify")
    public String modify(Department department, Model model, HttpSession session) {
        try {
            // 调用服务层修改科室：业务逻辑由Service层处理（如数据校验、数据库更新）
            departmentService.modify(department);
            // 修改成功：移除会话中残留的临时数据（避免下次编辑干扰）
            session.removeAttribute("modifyDepartment");
            // 存入成功消息：供列表页显示"科室修改成功！"
            session.setAttribute("successMessage", "科室修改成功！");
            // 重定向到列表页：避免表单重复提交
            return "redirect:find";
        } catch (RuntimeException e) {
            // 捕获业务异常（如"科室名称重复"）
            // 保存用户输入到会话：用于编辑页回显
            session.setAttribute("modifyDepartment", department);
            // 传递错误消息到视图：显示具体业务问题
            model.addAttribute("errorMessage", e.getMessage());
            // 重新传递医院列表：编辑页下拉框需重新加载
            model.addAttribute("hospitalList", hospitalService.findAll());
            // 返回编辑页：让用户修正错误
            return "backend/department/edit";
        } catch (Exception e) {
            // 捕获系统异常（如数据库错误）
            // 保存用户输入到会话：表单回显
            session.setAttribute("modifyDepartment", department);
            // 传递通用错误消息：隐藏系统细节
            model.addAttribute("errorMessage", "修改失败: " + e.getMessage());
            // 传递医院列表：确保下拉框正常显示
            model.addAttribute("hospitalList", hospitalService.findAll());
            // 返回编辑页：用户可重试
            return "backend/department/edit";
        }
    }

    /**
     * 删除科室（根据科室ID）
     * @param deptId 科室ID：从URL获取，前端点击"删除"按钮传递
     * @param session HTTP会话对象：存储删除成功/失败的消息
     * @return 重定向到科室列表页（无论成功失败，均返回列表页）
     */
    // 10. 方法：删除科室（处理GET请求）
    // GET请求映射：URL为"/department/removeById?deptId=xxx"，删除按钮触发
    @GetMapping("/removeById")
    // 注释说明：事务应在Service层控制（Controller层仅做请求分发，不处理业务原子性）
    // 注意：Controller层不需要添加@Transactional注解，事务应该在Service层控制
    public String removeById(@RequestParam("deptId") Long deptId, HttpSession session) {
        // 打印调试日志：记录接收到的删除请求（便于排查问题）
        System.out.println("接收到科室删除请求，科室ID: " + deptId);
        try {
            // 调用服务层删除科室：Service层会处理关联数据校验（如科室下是否有医生）
            departmentService.removeById(deptId);
            // 存入删除成功消息：供列表页显示
            session.setAttribute("successMessage", "科室删除成功！");
            // 打印调试日志：记录删除成功
            System.out.println("科室删除成功，科室ID: " + deptId);
        } catch (RuntimeException e) {
            // 捕获业务异常（如"科室下有关联医生，无法删除"）
            // 拼接错误消息：包含具体业务原因
            String errorMsg = "删除失败：" + e.getMessage();
            // 打印错误日志：便于开发人员定位问题
            System.out.println(errorMsg); // 打印错误信息到控制台，方便调试
            // 存入错误消息：供列表页显示
            session.setAttribute("errorMessage", errorMsg);
        } catch (Exception e) {
            // 捕获系统异常（如数据库连接失败）
            // 拼接通用错误消息
            String errorMsg = "删除失败：系统错误，请稍后重试";
            // 打印错误日志：包含异常详情（堆栈信息）
            System.out.println(errorMsg + ": " + e.getMessage()); // 打印错误信息到控制台，方便调试
            e.printStackTrace(); // 打印异常堆栈，便于排查底层问题
            // 存入错误消息：供列表页显示
            session.setAttribute("errorMessage", errorMsg);
        }
        // 重定向到列表页：无论成功失败，均返回列表页查看结果
        return "redirect:find"; // 删除成功后重定向到科室列表页面
    }

    /**
     * 获取所有科室数据（供其他模块的下拉列表使用）
     * @return 所有科室的列表（序列化为JSON格式返回）
     */
    // 11. 方法：获取所有科室（供其他模块下拉选择，处理GET请求）
    // GET请求映射：URL为"/department/getAllDepartments"，如医生管理模块加载科室下拉框
    @GetMapping("/getAllDepartments")
    // 响应体注解：将方法返回的List<Department>直接序列化为JSON（而非跳转视图）
    @ResponseBody
    public List<Department> getAllDepartments() {
        try {
            // 打印调试日志：记录数据查询开始
            System.out.println("开始获取所有科室数据...");
            // 调用服务层查询所有科室：无分页，返回全部数据
            List<Department> departments = departmentService.findAll();
            // 打印调试日志：记录查询到的科室数量
            System.out.println("获取到科室数量: " + (departments != null ? departments.size() : 0));
            // 返回科室列表：自动序列化为JSON（前端下拉组件可直接解析）
            return departments;
        } catch (Exception e) {
            // 捕获异常：查询失败时返回空列表（避免前端因接收null报错）
            System.err.println("获取科室数据时发生错误: " + e.getMessage()); // 打印错误日志
            e.printStackTrace(); // 打印异常堆栈
            return new ArrayList<>(); // 返回空列表，保证前端正常渲染
        }
    }
}
